package clientN

import (
	"encoding/json"
	"fmt"
	"log"
	"sync"
	"wxp2p/common"

	"github.com/pion/webrtc/v3"
)

type WebrtcAnswer struct {
	WebrtcId             int32
	DataSendChan         chan []byte
	DataRecvChan         chan []byte
	peerConnection       *webrtc.PeerConnection
	pendingCandidatesMux *sync.Mutex
	pendingCandidates    []*webrtc.ICECandidate
	signalClient         *ServerClient
	tcpServer            *TCPServer
	hpPeer               *common.HostPortPeer
}

var GWebrtcId int32 = 0

func NewWebrtcAnswer(hpPeer *common.HostPortPeer, sc *ServerClient) *WebrtcAnswer {
	wa := WebrtcAnswer{hpPeer: hpPeer, signalClient: sc}
	GWebrtcId += 1
	wa.WebrtcId = GWebrtcId
	wa.DataRecvChan = make(chan []byte)
	wa.DataSendChan = make(chan []byte)
	return &wa
}

func (wa *WebrtcAnswer) SignalHandler(sig common.P2PSignal) {
	switch sig.SigType {
	case common.ECandidate: //另一个客户端的打洞信息，即对外暴露的外网地址
		if candidateErr := wa.peerConnection.AddICECandidate(webrtc.ICECandidateInit{Candidate: string(sig.Content)}); candidateErr != nil {
			common.LogDebug(candidateErr)
		}
	case common.ESdp: //接收另一个客户端的连接信息
		sdp := webrtc.SessionDescription{}
		json.Unmarshal([]byte(sig.Content), &sdp)
		if err := wa.peerConnection.SetRemoteDescription(sdp); err != nil {
			common.LogDebug(err)
		}
		// Create an answer to send to the other process
		answer, err := wa.peerConnection.CreateAnswer(nil)
		if err != nil {
			common.LogDebug(err)
		}
		payload, err := json.Marshal(answer)
		if err != nil {
			common.LogDebug(err)
		}

		p2psig := common.P2PSignal{WebrtcId: wa.WebrtcId, SigType: common.ESdp, Content: string(payload)}
		wa.signalClient.SendChan <- p2psig

		// Sets the LocalDescription, and starts our UDP listeners
		err = wa.peerConnection.SetLocalDescription(answer)
		if err != nil {
			common.LogDebug(err)
		}

		wa.pendingCandidatesMux.Lock()
		for _, c := range wa.pendingCandidates {
			p2psig := common.P2PSignal{WebrtcId: wa.WebrtcId, SigType: common.ECandidate, Content: c.ToJSON().Candidate}
			wa.signalClient.SendChan <- p2psig
		}
		wa.pendingCandidatesMux.Unlock()
	}
}

func (wa *WebrtcAnswer) Run() {
	go wa.DataRecvLoop()
	go wa.WebrtcLoop()
}

func (wa *WebrtcAnswer) CLose() {
	wa.peerConnection.Close()
	close(wa.DataRecvChan)
}

func (wa *WebrtcAnswer) WebrtcLoop() {
	log.Println("重置连接状态-等待连接")
	done := make(chan struct{})
	closeThread1 := make(chan struct{})
	closeThread2 := make(chan struct{})

	wa.pendingCandidatesMux = &sync.Mutex{}
	wa.pendingCandidates = make([]*webrtc.ICECandidate, 0)
	// Create a new RTCPeerConnection
	peerConnection, err := webrtc.NewPeerConnection(common.WebrtcConfig)
	wa.peerConnection = peerConnection
	if err != nil {
		log.Println(err)
	}
	defer func() {
		if err := wa.peerConnection.Close(); err != nil {
			fmt.Printf("cannot close peerConnection: %v\n", err)
		}
		close(closeThread1)
		close(closeThread2)
		delete(wa.signalClient.WebrtcArray, wa.WebrtcId)
	}()

	wa.peerConnection.OnICECandidate(func(c *webrtc.ICECandidate) {
		if c == nil {
			return
		}
		wa.pendingCandidatesMux.Lock()
		defer wa.pendingCandidatesMux.Unlock()
		desc := wa.peerConnection.RemoteDescription()
		if desc == nil {
			wa.pendingCandidates = append(wa.pendingCandidates, c)
		} else {
			sig := common.P2PSignal{WebrtcId: wa.WebrtcId, SigType: common.ECandidate, Content: c.ToJSON().Candidate}
			wa.signalClient.SendChan <- sig
		}
	})

	wa.peerConnection.OnConnectionStateChange(func(s webrtc.PeerConnectionState) {
		log.Printf("p2p连接状态改变: %s\n", s.String())
		if s == webrtc.PeerConnectionStateConnected {
			log.Println("p2p连接成功")
		}
		if s == webrtc.PeerConnectionStateFailed || s == webrtc.PeerConnectionStateDisconnected {
			log.Println("p2p连接失败正在退出")
			close(done) //退出此线程及所有子线程
			// go wa.WebrtcLoop() //重新等待连接//改为主动命令
		}
	})

	wa.peerConnection.OnDataChannel(func(d *webrtc.DataChannel) {
		d.OnOpen(func() {
			log.Println("p2p数据通道准备就绪")
			wa.tcpServer = NewTCPServer(wa.hpPeer.RemoteHost, wa.hpPeer.RemotePort, wa)
			go func() {
				for {
					select {
					case <-closeThread2:
						common.LogDebug("退出子线程")
						return
					case buf := <-wa.DataSendChan:
						sendErr := d.Send(buf)
						if sendErr != nil {
							common.LogDebug(sendErr)
						}
					}
				}
			}()
		})

		// Register text message handling
		d.OnMessage(func(msg webrtc.DataChannelMessage) {
			wa.DataRecvChan <- msg.Data
		})
	})
	content, _ := json.Marshal(wa.hpPeer)
	sig := common.P2PSignal{WebrtcId: wa.WebrtcId, SigType: common.ECreateAnswerOK, Content: string(content)}
	wa.signalClient.SendChan <- sig
	// block
	<-done
}

func (wa *WebrtcAnswer) DataRecvLoop() {
	for buf := range wa.DataRecvChan {
		if wa.tcpServer != nil {
			wa.tcpServer.ServerRecvChanHandler(buf)
		}
	}
	common.LogDebug("退出webrtc datarecvloop")
}
